From the potential outcomes framework to the intent to treat (ITT) and complier average treatment effects (CACE aka LATE).

Generating up our population

Lets define and generate the population we’re going to study.

population_size <- 1000000
base_income <- 10000
base_income_sd <- 1000

ethnicities <- c("Indian", "Asian", "Black", "Hispanic", "White", "Arabic")
genders <- c("Female", "Male")

demographics <- tibble(
  gender = sample(0:1, population_size, prob = runif(length(genders)),
                  replace = TRUE),
  ethnicity = sample(1:6, population_size, prob = runif(length(ethnicities)),
                     replace = TRUE)
)

How many people have we defined to be in our population?

What is their expected base income?

How many ethnicities are in our population?

population <- randomNames(population_size, return.complete.data = TRUE,
                          gender = demographics$gender,
                          ethnicity = demographics$ethnicity) %>%
  mutate(id = row_number()) %>%
  mutate(across(where(is.character), as.factor)) %>%
  mutate(income = round(rnorm(population_size, base_income, base_income_sd))) %>%
  mutate(income = income + income * (gender * 0.2)) %>%
  mutate(income = income + income * (ethnicity * 0.1)) %>%
  mutate(gender = map_chr(gender, ~ genders[.x + 1]),
         ethnicity = map_chr(ethnicity, ~ ethnicities[.x]))

summary(population)
    gender           ethnicity               first_name        last_name     
 Length:1000000     Length:1000000     Michael    : 10737   Johnson :  7085  
 Class :character   Class :character   Joshua     : 10045   Nguyen  :  6910  
 Mode  :character   Mode  :character   Brandon    :  9018   Smith   :  6826  
                                       Christopher:  8080   Martinez:  6803  
                                       Tyler      :  7506   Williams:  5515  
                                       Matthew    :  7255   Garcia  :  4841  
                                       (Other)    :947359   (Other) :962020  
       id              income     
 Min.   :      1   Min.   : 5808  
 1st Qu.: 250001   1st Qu.:12194  
 Median : 500000   Median :13879  
 Mean   : 500000   Mean   :14090  
 3rd Qu.: 750000   3rd Qu.:15726  
 Max.   :1000000   Max.   :26394  
                                  
population %>%
  ggplot(aes(ethnicity, fill = ethnicity)) +
  geom_bar()


population %>%
  ggplot(aes(gender, fill = gender)) +
  geom_bar()


population %>%
  ggplot(aes(income)) +
  geom_density() +
  facet_grid(ethnicity ~ gender)

How much more/less income do males make compared to females?

On average, which ethnicity makes the most?

On average, which ethnicity makes the least?

Are there any significant differences in the proportion of genders? If so, which?

Are there any significant differences in the proportion of ethnicities? If so, which?

Creating our treatment effect (God-mode)

Now that we have a population, we will generate the effects that the policy will have on each individual. Since we have full knowledge and control of this experiment, we will know and define the treatment effect for each individual, along with both of their potential outcomes (with and without treatment). The researcher will not know these values, it is their job to recover these values.

effect_size <- 3000
effect_sd <- 1000

population <- population %>%
  mutate(potential_0 = income * 0.9) %>%
  mutate(potential_1 = round(
    potential_0 + rnorm(population_size, effect_size, effect_sd)))

population %>%
  pivot_longer(c(potential_0, potential_1)) %>%
  ggplot(aes(value, fill = name)) +
  geom_density(alpha = 0.2)

What the mean and standard deviation of the potential outcomes without treatment?

What the mean and standard deviation of the potential outcomes with treatment?

What is our expected average treatment effect?

Sampling from the population (researcher mode)

As a researcher, we don’t have access to the full population. We typically have a limited set of people we can include in our research study. The first thing we need to do is obtain a study sample from the population. If we have a registry or census with everyone person from the population, we could randomly sample from it.

Estimating the Average Treatment Effect (researcher-mode)

Now we’re the researcher and we’re given different sample sizes from the population to try to estimate our treatment effect.

sample_sizes <- 10 ^ seq(1, log(population_size, 10))

What are the different sample sizes we will work with as a researcher?

Does the researcher know the values of both potential outcomes for the individuals in their sample?

Describe, in a few sentences, how you would try to estimate the ATE from the samples we are given?

Full compliance

First we simulate the RCT with each of the sample sizes from above with Full Compliance.

What are the four different types of individuals in our sample and which of those individuals are assumed to exist and not exist under full compliance?

The code below simulates random assignment of treatment for each sample size and tries to calculate the observed average treatment effect.

The first row is a summary row taking the average of all of the individual rows below it. The only thing that changes from table to table is the number of individuals in that sample, notice the number of rows in each table in the bottom left hand corner. Scroll to the right to see all the columns.

invisible(lapply(sample_sizes, function(sample_size) {
  experiment <- population %>%
    sample_n(sample_size) %>%
    # select(id, first_name, starts_with("potential_")) %>%
    mutate(unit_tx_effect = potential_1 - potential_0) %>%
    arrange(runif(n())) %>%
    mutate(group = if_else(row_number() <= n() / 2, "treatment", "control")) %>%
    arrange(id) %>%
    mutate(observed_0 = if_else(group == "control", potential_0,
                                        NA_real_),
           observed_1 = if_else(group == "treatment", potential_1,
                                        NA_real_)) %>%
    bind_rows(summarise(., across(where(is.numeric), mean, na.rm = TRUE)) %>%
                ungroup() %>%
                mutate(across(where(is.numeric), round, digits = 1),
                       across(where(is.factor), ~ "<<SUMMARY>>"),
                       id = NA)) %>%
    mutate(observed_ate = observed_1 - observed_0) %>%
    arrange(desc(row_number())) %>%
  select(-id) %>% print()
}))

Try to explain what each column name is referring to.

Why are there NA values in observed_0 and observed_1 columns?

What is the relationship between potential_0, potential_1, and unit_tx_effect?

What is the relatinoship between observed_0, observed_1 and observed_ate?*

What is our actual treatment effect? What do you notice about the observed ATE as the sample increases?*

Non-compliance

Here we do the same exercise as above but consider the case where we have non-compliers. Specifically we have 60% compliers, 20% never-takers and 20% always-takers. We assume defiers don’t exist here. Instead of estimating just the ATE, we’re now estimating the intent-to-treat effect (ITT) and the Complier Average Causal Effect (CACE aka LATE) which is the ATE for the compliers.

Scroll to the right to see all the columns.

#  (3/5 complier, 1/5 nevertaker, 1/5 alwaystaker)
complier_types <- c("alwaystaker", "alwaystaker",
                    "nevertaker", "nevertaker",
                    "complier", "complier", "complier",
                    "complier", "complier", "complier")

invisible(lapply(sample_sizes, function(sample_size) {
  population %>%
    # select sample_size units randomly
    sample_n(sample_size) %>%
    # select client name and potential outcomes
    select(first_name, starts_with("potential_")) %>%
    # calculate true unit-level treatment effect
    mutate(unit_tx_effect = potential_1 - potential_0) %>%
    # randomly assign treatment and control (50/50)
    arrange(runif(n())) %>%
    mutate(group = if_else(row_number() < n() / 2, "treatment", "control")) %>%
    arrange(runif(n())) %>%
    # randomly assign complier types
    # mutate(compliance_group = complier_types[ntile(runif(n()), n = 5)]) %>%
    mutate(compliance_group = complier_types[floor(10 * runif(n())) + 1]) %>%
    # set observed outcomes based on control and treatment assignment
    mutate(observed_0 = if_else(group == "control", potential_0,
                                        NA_real_),
           observed_1 = if_else(group == "treatment", potential_1,
                                        NA_real_)) %>%
    # set observed outcomes based on complier type
    mutate(
      observed_0 = if_else(
        compliance_group == "alwaystaker" & !is.na(observed_0), potential_1,
        observed_0),
      observed_1 = if_else(
        compliance_group == "nevertaker" & !is.na(observed_1), potential_0,
        observed_1)) %>%
    # complier type shares
    mutate(is_taker_tx = if_else(
             group == "treatment",
             compliance_group %in% c("alwaystaker", "complier"), NA),
           is_taker_ctl = if_else(
             group == "control",
             compliance_group %in% c("alwaystaker"), NA)) %>%
    # calculate summaries
    bind_rows(
      summarise(., across(starts_with(c("observed_", "is_")), mean, na.rm = TRUE)) %>%
        mutate(across(where(is.numeric), round, digits = 1), first_name = "<<SUMMARY>>")
    ) %>%
    mutate(observed_itt_effect = observed_1 - observed_0) %>%
    arrange(desc(row_number())) %>%
    mutate(alpha = is_taker_tx - is_taker_ctl,
           cace = observed_itt_effect / alpha) %>%
    print()
}))

Building from your knowledge from the last exercise, describe the new columns in these tables: is_taker_tx, is_taker_ctl, observed_itt_effect, alpha, and cace.

What is the relationship between is_taker_tx, is_taker_ctl, and alpha?

What is the relationship between obs_itt, obs_alpha, and obs_cace? (obs = observed)

What do you notice about alpha and cace as the sample size increases?

LS0tCnRpdGxlOiAiUG90ZW50aWFsIE91dGNvbWVzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpGcm9tIHRoZSBwb3RlbnRpYWwgb3V0Y29tZXMgZnJhbWV3b3JrIHRvIHRoZSBpbnRlbnQgdG8gdHJlYXQgKElUVCkgYW5kIGNvbXBsaWVyIGF2ZXJhZ2UgdHJlYXRtZW50IGVmZmVjdHMgKENBQ0UgYWthIExBVEUpLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikKaW5zdGFsbC5wYWNrYWdlcygicmFuZG9tTmFtZXMiKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyYW5kb21OYW1lcykKYGBgCgojIyBHZW5lcmF0aW5nIHVwIG91ciBwb3B1bGF0aW9uCgpMZXRzIGRlZmluZSBhbmQgZ2VuZXJhdGUgdGhlIHBvcHVsYXRpb24gd2UncmUgZ29pbmcgdG8gc3R1ZHkuCgpgYGB7cn0KcG9wdWxhdGlvbl9zaXplIDwtIDEwMDAwMDAKYmFzZV9pbmNvbWUgPC0gMTAwMDAKYmFzZV9pbmNvbWVfc2QgPC0gMTAwMAoKZXRobmljaXRpZXMgPC0gYygiSW5kaWFuIiwgIkFzaWFuIiwgIkJsYWNrIiwgIkhpc3BhbmljIiwgIldoaXRlIiwgIkFyYWJpYyIpCmdlbmRlcnMgPC0gYygiRmVtYWxlIiwgIk1hbGUiKQoKZGVtb2dyYXBoaWNzIDwtIHRpYmJsZSgKICBnZW5kZXIgPSBzYW1wbGUoMDoxLCBwb3B1bGF0aW9uX3NpemUsIHByb2IgPSBydW5pZihsZW5ndGgoZ2VuZGVycykpLAogICAgICAgICAgICAgICAgICByZXBsYWNlID0gVFJVRSksCiAgZXRobmljaXR5ID0gc2FtcGxlKDE6NiwgcG9wdWxhdGlvbl9zaXplLCBwcm9iID0gcnVuaWYobGVuZ3RoKGV0aG5pY2l0aWVzKSksCiAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2UgPSBUUlVFKQopCmBgYAoKKipIb3cgbWFueSBwZW9wbGUgaGF2ZSB3ZSBkZWZpbmVkIHRvIGJlIGluIG91ciBwb3B1bGF0aW9uPyoqCgoqKldoYXQgaXMgdGhlaXIgZXhwZWN0ZWQgYmFzZSBpbmNvbWU/KioKCioqSG93IG1hbnkgZXRobmljaXRpZXMgYXJlIGluIG91ciBwb3B1bGF0aW9uPyoqCgpgYGB7cn0KcG9wdWxhdGlvbiA8LSByYW5kb21OYW1lcyhwb3B1bGF0aW9uX3NpemUsIHJldHVybi5jb21wbGV0ZS5kYXRhID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5kZXIgPSBkZW1vZ3JhcGhpY3MkZ2VuZGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgIGV0aG5pY2l0eSA9IGRlbW9ncmFwaGljcyRldGhuaWNpdHkpICU+JQogIG11dGF0ZShpZCA9IHJvd19udW1iZXIoKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5jaGFyYWN0ZXIpLCBhcy5mYWN0b3IpKSAlPiUKICBtdXRhdGUoaW5jb21lID0gcm91bmQocm5vcm0ocG9wdWxhdGlvbl9zaXplLCBiYXNlX2luY29tZSwgYmFzZV9pbmNvbWVfc2QpKSkgJT4lCiAgbXV0YXRlKGluY29tZSA9IGluY29tZSArIGluY29tZSAqIChnZW5kZXIgKiAwLjIpKSAlPiUKICBtdXRhdGUoaW5jb21lID0gaW5jb21lICsgaW5jb21lICogKGV0aG5pY2l0eSAqIDAuMSkpICU+JQogIG11dGF0ZShnZW5kZXIgPSBtYXBfY2hyKGdlbmRlciwgfiBnZW5kZXJzWy54ICsgMV0pLAogICAgICAgICBldGhuaWNpdHkgPSBtYXBfY2hyKGV0aG5pY2l0eSwgfiBldGhuaWNpdGllc1sueF0pKQoKc3VtbWFyeShwb3B1bGF0aW9uKQoKcG9wdWxhdGlvbiAlPiUKICBnZ3Bsb3QoYWVzKGV0aG5pY2l0eSwgZmlsbCA9IGV0aG5pY2l0eSkpICsKICBnZW9tX2JhcigpCgpwb3B1bGF0aW9uICU+JQogIGdncGxvdChhZXMoZ2VuZGVyLCBmaWxsID0gZ2VuZGVyKSkgKwogIGdlb21fYmFyKCkKCnBvcHVsYXRpb24gJT4lCiAgZ2dwbG90KGFlcyhpbmNvbWUpKSArCiAgZ2VvbV9kZW5zaXR5KCkgKwogIGZhY2V0X2dyaWQoZXRobmljaXR5IH4gZ2VuZGVyKQpgYGAKCioqSG93IG11Y2ggbW9yZS9sZXNzIGluY29tZSBkbyBtYWxlcyBtYWtlIGNvbXBhcmVkIHRvIGZlbWFsZXM/KioKCioqT24gYXZlcmFnZSwgd2hpY2ggZXRobmljaXR5IG1ha2VzIHRoZSBtb3N0PyoqCgoqKk9uIGF2ZXJhZ2UsIHdoaWNoIGV0aG5pY2l0eSBtYWtlcyB0aGUgbGVhc3Q/KioKCioqQXJlIHRoZXJlIGFueSBzaWduaWZpY2FudCBkaWZmZXJlbmNlcyBpbiB0aGUgcHJvcG9ydGlvbiBvZiBnZW5kZXJzPyBJZiBzbywgd2hpY2g/KioKCioqQXJlIHRoZXJlIGFueSBzaWduaWZpY2FudCBkaWZmZXJlbmNlcyBpbiB0aGUgcHJvcG9ydGlvbiBvZiBldGhuaWNpdGllcz8gSWYgc28sIHdoaWNoPyoqCgojIyBDcmVhdGluZyBvdXIgdHJlYXRtZW50IGVmZmVjdCAoR29kLW1vZGUpCgpOb3cgdGhhdCB3ZSBoYXZlIGEgcG9wdWxhdGlvbiwgd2Ugd2lsbCBnZW5lcmF0ZSB0aGUgZWZmZWN0cyB0aGF0IHRoZSBwb2xpY3kgX3dpbGxfIGhhdmUgb24gZWFjaCBpbmRpdmlkdWFsLiBTaW5jZSB3ZSBoYXZlIGZ1bGwga25vd2xlZGdlIGFuZCBjb250cm9sIG9mIHRoaXMgZXhwZXJpbWVudCwgd2Ugd2lsbCBrbm93IGFuZCBkZWZpbmUgdGhlIHRyZWF0bWVudCBlZmZlY3QgZm9yIGVhY2ggaW5kaXZpZHVhbCwgYWxvbmcgd2l0aCBib3RoIG9mIHRoZWlyIHBvdGVudGlhbCBvdXRjb21lcyAod2l0aCBhbmQgd2l0aG91dCB0cmVhdG1lbnQpLiBUaGUgcmVzZWFyY2hlciB3aWxsIF9ub3RfIGtub3cgdGhlc2UgdmFsdWVzLCBpdCBpcyB0aGVpciBqb2IgdG8gcmVjb3ZlciB0aGVzZSB2YWx1ZXMuCgpgYGB7cn0KZWZmZWN0X3NpemUgPC0gMzAwMAplZmZlY3Rfc2QgPC0gMTAwMAoKcG9wdWxhdGlvbiA8LSBwb3B1bGF0aW9uICU+JQogIG11dGF0ZShwb3RlbnRpYWxfMCA9IGluY29tZSAqIDAuOSkgJT4lCiAgbXV0YXRlKHBvdGVudGlhbF8xID0gcm91bmQoCiAgICBwb3RlbnRpYWxfMCArIHJub3JtKHBvcHVsYXRpb25fc2l6ZSwgZWZmZWN0X3NpemUsIGVmZmVjdF9zZCkpKQoKcG9wdWxhdGlvbiAlPiUKICBwaXZvdF9sb25nZXIoYyhwb3RlbnRpYWxfMCwgcG90ZW50aWFsXzEpKSAlPiUKICBnZ3Bsb3QoYWVzKHZhbHVlLCBmaWxsID0gbmFtZSkpICsKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjIpCmBgYAoKKipXaGF0IHRoZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHBvdGVudGlhbCBvdXRjb21lcyB3aXRob3V0IHRyZWF0bWVudD8qKgoKKipXaGF0IHRoZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHBvdGVudGlhbCBvdXRjb21lcyB3aXRoIHRyZWF0bWVudD8qKgoKKipXaGF0IGlzIG91ciBleHBlY3RlZCBhdmVyYWdlIHRyZWF0bWVudCBlZmZlY3Q/KioKCiMjIFNhbXBsaW5nIGZyb20gdGhlIHBvcHVsYXRpb24gKHJlc2VhcmNoZXIgbW9kZSkKCkFzIGEgcmVzZWFyY2hlciwgd2UgZG9uJ3QgaGF2ZSBhY2Nlc3MgdG8gdGhlIGZ1bGwgcG9wdWxhdGlvbi4gV2UgdHlwaWNhbGx5IGhhdmUgYSBsaW1pdGVkIHNldCBvZiBwZW9wbGUgd2UgY2FuIGluY2x1ZGUgaW4gb3VyIHJlc2VhcmNoIHN0dWR5LiBUaGUgZmlyc3QgdGhpbmcgd2UgbmVlZCB0byBkbyBpcyBvYnRhaW4gYSBzdHVkeSBzYW1wbGUgZnJvbSB0aGUgcG9wdWxhdGlvbi4gSWYgd2UgaGF2ZSBhIHJlZ2lzdHJ5IG9yIGNlbnN1cyB3aXRoIGV2ZXJ5b25lIHBlcnNvbiBmcm9tIHRoZSBwb3B1bGF0aW9uLCB3ZSBjb3VsZCByYW5kb21seSBzYW1wbGUgZnJvbSBpdC4KCmBgYHtyfQoKYGBgCgoKIyMgRXN0aW1hdGluZyB0aGUgQXZlcmFnZSBUcmVhdG1lbnQgRWZmZWN0IChyZXNlYXJjaGVyLW1vZGUpCgpOb3cgd2UncmUgdGhlIHJlc2VhcmNoZXIgYW5kIHdlJ3JlIGdpdmVuIGRpZmZlcmVudCBzYW1wbGUgc2l6ZXMgZnJvbSB0aGUgcG9wdWxhdGlvbiB0byB0cnkgdG8gZXN0aW1hdGUgb3VyIHRyZWF0bWVudCBlZmZlY3QuCgpgYGB7cn0Kc2FtcGxlX3NpemVzIDwtIDEwIF4gc2VxKDEsIGxvZyhwb3B1bGF0aW9uX3NpemUsIDEwKSkKYGBgCgoqKldoYXQgYXJlIHRoZSBkaWZmZXJlbnQgc2FtcGxlIHNpemVzIHdlIHdpbGwgd29yayB3aXRoIGFzIGEgcmVzZWFyY2hlcj8qKgoKKipEb2VzIHRoZSByZXNlYXJjaGVyIGtub3cgdGhlIHZhbHVlcyBvZiBib3RoIHBvdGVudGlhbCBvdXRjb21lcyBmb3IgdGhlIGluZGl2aWR1YWxzIGluIHRoZWlyIHNhbXBsZT8qKgoKKipEZXNjcmliZSwgaW4gYSBmZXcgc2VudGVuY2VzLCBob3cgeW91IHdvdWxkIHRyeSB0byBlc3RpbWF0ZSB0aGUgQVRFIGZyb20gdGhlIHNhbXBsZXMgd2UgYXJlIGdpdmVuPyoqCgojIyMgRnVsbCBjb21wbGlhbmNlCgpGaXJzdCB3ZSBzaW11bGF0ZSB0aGUgUkNUIHdpdGggZWFjaCBvZiB0aGUgc2FtcGxlIHNpemVzIGZyb20gYWJvdmUgd2l0aCBfRnVsbCBDb21wbGlhbmNlXy4KCioqV2hhdCBhcmUgdGhlIGZvdXIgZGlmZmVyZW50IHR5cGVzIG9mIGluZGl2aWR1YWxzIGluIG91ciBzYW1wbGUgYW5kIHdoaWNoIG9mIHRob3NlIGluZGl2aWR1YWxzIGFyZSBhc3N1bWVkIHRvIGV4aXN0IGFuZCBub3QgZXhpc3QgdW5kZXIgZnVsbCBjb21wbGlhbmNlPyoqCgpUaGUgY29kZSBiZWxvdyBzaW11bGF0ZXMgcmFuZG9tIGFzc2lnbm1lbnQgb2YgdHJlYXRtZW50IGZvciBlYWNoIHNhbXBsZSBzaXplIGFuZCB0cmllcyB0byBjYWxjdWxhdGUgdGhlIG9ic2VydmVkIGF2ZXJhZ2UgdHJlYXRtZW50IGVmZmVjdC4KClRoZSBmaXJzdCByb3cgaXMgYSBzdW1tYXJ5IHJvdyB0YWtpbmcgdGhlIGF2ZXJhZ2Ugb2YgYWxsIG9mIHRoZSBpbmRpdmlkdWFsIHJvd3MgYmVsb3cgaXQuIFRoZSBvbmx5IHRoaW5nIHRoYXQgY2hhbmdlcyBmcm9tIHRhYmxlIHRvIHRhYmxlIGlzIHRoZSBudW1iZXIgb2YgaW5kaXZpZHVhbHMgaW4gdGhhdCBzYW1wbGUsIG5vdGljZSB0aGUgbnVtYmVyIG9mIHJvd3MgaW4gZWFjaCB0YWJsZSBpbiB0aGUgYm90dG9tIGxlZnQgaGFuZCBjb3JuZXIuIFNjcm9sbCB0byB0aGUgcmlnaHQgdG8gc2VlIGFsbCB0aGUgY29sdW1ucy4KCmBgYHtyfQppbnZpc2libGUobGFwcGx5KHNhbXBsZV9zaXplcywgZnVuY3Rpb24oc2FtcGxlX3NpemUpIHsKICBwb3B1bGF0aW9uICU+JQogICAgc2FtcGxlX24oc2FtcGxlX3NpemUpICU+JQogICAgIyBzZWxlY3QoaWQsIGZpcnN0X25hbWUsIHN0YXJ0c193aXRoKCJwb3RlbnRpYWxfIikpICU+JQogICAgbXV0YXRlKHVuaXRfdHhfZWZmZWN0ID0gcG90ZW50aWFsXzEgLSBwb3RlbnRpYWxfMCkgJT4lCiAgICBhcnJhbmdlKHJ1bmlmKG4oKSkpICU+JQogICAgbXV0YXRlKGdyb3VwID0gaWZfZWxzZShyb3dfbnVtYmVyKCkgPD0gbigpIC8gMiwgInRyZWF0bWVudCIsICJjb250cm9sIikpICU+JQogICAgYXJyYW5nZShpZCkgJT4lCiAgICBtdXRhdGUob2JzZXJ2ZWRfMCA9IGlmX2Vsc2UoZ3JvdXAgPT0gImNvbnRyb2wiLCBwb3RlbnRpYWxfMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BX3JlYWxfKSwKICAgICAgICAgICBvYnNlcnZlZF8xID0gaWZfZWxzZShncm91cCA9PSAidHJlYXRtZW50IiwgcG90ZW50aWFsXzEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQV9yZWFsXykpICU+JQogICAgYmluZF9yb3dzKAogICAgICBzdW1tYXJpc2UoLiwgYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCBtZWFuLCBuYS5ybSA9IFRSVUUpKSAlPiUKICAgICAgICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCByb3VuZCwgZGlnaXRzID0gMSksCiAgICAgICAgICAgICAgIGFjcm9zcyh3aGVyZShpcy5jaGFyYWN0ZXIpLCB+ICI8PFNVTU1BUlk+PiIpLAogICAgICAgICAgICAgICBpZCA9IE5BKSkgJT4lCiAgICBtdXRhdGUob2JzZXJ2ZWRfYXRlID0gb2JzZXJ2ZWRfMSAtIG9ic2VydmVkXzApICU+JQogICAgYXJyYW5nZShkZXNjKHJvd19udW1iZXIoKSkpICU+JQogIHNlbGVjdCgtaWQpICU+JSBwcmludCgpCn0pKQpgYGAKCioqVHJ5IHRvIGV4cGxhaW4gd2hhdCBlYWNoIGNvbHVtbiBuYW1lIGlzIHJlZmVycmluZyB0by4qKgoKKipXaHkgYXJlIHRoZXJlIE5BIHZhbHVlcyBpbiBvYnNlcnZlZF8wIGFuZCBvYnNlcnZlZF8xIGNvbHVtbnM/KioKCioqV2hhdCBpcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gcG90ZW50aWFsXzAsIHBvdGVudGlhbF8xLCBhbmQgdW5pdF90eF9lZmZlY3Q/KioKCioqV2hhdCBpcyB0aGUgcmVsYXRpbm9zaGlwIGJldHdlZW4gb2JzZXJ2ZWRfMCwgb2JzZXJ2ZWRfMSBhbmQgb2JzZXJ2ZWRfYXRlPyoqKgoKKipXaGF0IGlzIG91ciBhY3R1YWwgdHJlYXRtZW50IGVmZmVjdD8gV2hhdCBkbyB5b3Ugbm90aWNlIGFib3V0IHRoZSBvYnNlcnZlZCBBVEUgYXMgdGhlIHNhbXBsZSBpbmNyZWFzZXM/KioqCgojIyMgTm9uLWNvbXBsaWFuY2UgCgpIZXJlIHdlIGRvIHRoZSBzYW1lIGV4ZXJjaXNlIGFzIGFib3ZlIGJ1dCBjb25zaWRlciB0aGUgY2FzZSB3aGVyZSB3ZSBoYXZlIG5vbi1jb21wbGllcnMuIFNwZWNpZmljYWxseSB3ZSBoYXZlIDYwJSBjb21wbGllcnMsIDIwJSBuZXZlci10YWtlcnMgYW5kIDIwJSBhbHdheXMtdGFrZXJzLiBXZSBhc3N1bWUgZGVmaWVycyBkb24ndCBleGlzdCBoZXJlLiBJbnN0ZWFkIG9mIGVzdGltYXRpbmcganVzdCB0aGUgQVRFLCB3ZSdyZSBub3cgZXN0aW1hdGluZyB0aGUgaW50ZW50LXRvLXRyZWF0IGVmZmVjdCAoSVRUKSBhbmQgdGhlIENvbXBsaWVyIEF2ZXJhZ2UgQ2F1c2FsIEVmZmVjdCAoQ0FDRSBha2EgTEFURSkgd2hpY2ggaXMgdGhlIEFURSBmb3IgdGhlIGNvbXBsaWVycy4KClNjcm9sbCB0byB0aGUgcmlnaHQgdG8gc2VlIGFsbCB0aGUgY29sdW1ucy4KCmBgYHtyfQojICAoMy81IGNvbXBsaWVyLCAxLzUgbmV2ZXJ0YWtlciwgMS81IGFsd2F5c3Rha2VyKQpjb21wbGllcl90eXBlcyA8LSBjKCJhbHdheXN0YWtlciIsICJhbHdheXN0YWtlciIsCiAgICAgICAgICAgICAgICAgICAgIm5ldmVydGFrZXIiLCAibmV2ZXJ0YWtlciIsCiAgICAgICAgICAgICAgICAgICAgImNvbXBsaWVyIiwgImNvbXBsaWVyIiwgImNvbXBsaWVyIiwKICAgICAgICAgICAgICAgICAgICAiY29tcGxpZXIiLCAiY29tcGxpZXIiLCAiY29tcGxpZXIiKQoKaW52aXNpYmxlKGxhcHBseShzYW1wbGVfc2l6ZXMsIGZ1bmN0aW9uKHNhbXBsZV9zaXplKSB7CiAgcG9wdWxhdGlvbiAlPiUKICAgICMgc2VsZWN0IHNhbXBsZV9zaXplIHVuaXRzIHJhbmRvbWx5CiAgICBzYW1wbGVfbihzYW1wbGVfc2l6ZSkgJT4lCiAgICAjIHNlbGVjdCBjbGllbnQgbmFtZSBhbmQgcG90ZW50aWFsIG91dGNvbWVzCiAgICBzZWxlY3QoZmlyc3RfbmFtZSwgc3RhcnRzX3dpdGgoInBvdGVudGlhbF8iKSkgJT4lCiAgICAjIGNhbGN1bGF0ZSB0cnVlIHVuaXQtbGV2ZWwgdHJlYXRtZW50IGVmZmVjdAogICAgbXV0YXRlKHVuaXRfdHhfZWZmZWN0ID0gcG90ZW50aWFsXzEgLSBwb3RlbnRpYWxfMCkgJT4lCiAgICAjIHJhbmRvbWx5IGFzc2lnbiB0cmVhdG1lbnQgYW5kIGNvbnRyb2wgKDUwLzUwKQogICAgYXJyYW5nZShydW5pZihuKCkpKSAlPiUKICAgIG11dGF0ZShncm91cCA9IGlmX2Vsc2Uocm93X251bWJlcigpIDwgbigpIC8gMiwgInRyZWF0bWVudCIsICJjb250cm9sIikpICU+JQogICAgYXJyYW5nZShydW5pZihuKCkpKSAlPiUKICAgICMgcmFuZG9tbHkgYXNzaWduIGNvbXBsaWVyIHR5cGVzCiAgICAjIG11dGF0ZShjb21wbGlhbmNlX2dyb3VwID0gY29tcGxpZXJfdHlwZXNbbnRpbGUocnVuaWYobigpKSwgbiA9IDUpXSkgJT4lCiAgICBtdXRhdGUoY29tcGxpYW5jZV9ncm91cCA9IGNvbXBsaWVyX3R5cGVzW2Zsb29yKDEwICogcnVuaWYobigpKSkgKyAxXSkgJT4lCiAgICAjIHNldCBvYnNlcnZlZCBvdXRjb21lcyBiYXNlZCBvbiBjb250cm9sIGFuZCB0cmVhdG1lbnQgYXNzaWdubWVudAogICAgbXV0YXRlKG9ic2VydmVkXzAgPSBpZl9lbHNlKGdyb3VwID09ICJjb250cm9sIiwgcG90ZW50aWFsXzAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOQV9yZWFsXyksCiAgICAgICAgICAgb2JzZXJ2ZWRfMSA9IGlmX2Vsc2UoZ3JvdXAgPT0gInRyZWF0bWVudCIsIHBvdGVudGlhbF8xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTkFfcmVhbF8pKSAlPiUKICAgICMgc2V0IG9ic2VydmVkIG91dGNvbWVzIGJhc2VkIG9uIGNvbXBsaWVyIHR5cGUKICAgIG11dGF0ZSgKICAgICAgb2JzZXJ2ZWRfMCA9IGlmX2Vsc2UoCiAgICAgICAgY29tcGxpYW5jZV9ncm91cCA9PSAiYWx3YXlzdGFrZXIiICYgIWlzLm5hKG9ic2VydmVkXzApLCBwb3RlbnRpYWxfMSwKICAgICAgICBvYnNlcnZlZF8wKSwKICAgICAgb2JzZXJ2ZWRfMSA9IGlmX2Vsc2UoCiAgICAgICAgY29tcGxpYW5jZV9ncm91cCA9PSAibmV2ZXJ0YWtlciIgJiAhaXMubmEob2JzZXJ2ZWRfMSksIHBvdGVudGlhbF8wLAogICAgICAgIG9ic2VydmVkXzEpKSAlPiUKICAgICMgY29tcGxpZXIgdHlwZSBzaGFyZXMKICAgIG11dGF0ZShpc190YWtlcl90eCA9IGlmX2Vsc2UoCiAgICAgICAgICAgICBncm91cCA9PSAidHJlYXRtZW50IiwKICAgICAgICAgICAgIGNvbXBsaWFuY2VfZ3JvdXAgJWluJSBjKCJhbHdheXN0YWtlciIsICJjb21wbGllciIpLCBOQSksCiAgICAgICAgICAgaXNfdGFrZXJfY3RsID0gaWZfZWxzZSgKICAgICAgICAgICAgIGdyb3VwID09ICJjb250cm9sIiwKICAgICAgICAgICAgIGNvbXBsaWFuY2VfZ3JvdXAgJWluJSBjKCJhbHdheXN0YWtlciIpLCBOQSkpICU+JQogICAgIyBjYWxjdWxhdGUgc3VtbWFyaWVzCiAgICBiaW5kX3Jvd3MoCiAgICAgIHN1bW1hcmlzZSguLCBhY3Jvc3Moc3RhcnRzX3dpdGgoYygib2JzZXJ2ZWRfIiwgImlzXyIpKSwgbWVhbiwgbmEucm0gPSBUUlVFKSkgJT4lCiAgICAgICAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgcm91bmQsIGRpZ2l0cyA9IDEpLCBmaXJzdF9uYW1lID0gIjw8U1VNTUFSWT4+IikKICAgICkgJT4lCiAgICBtdXRhdGUob2JzZXJ2ZWRfaXR0X2VmZmVjdCA9IG9ic2VydmVkXzEgLSBvYnNlcnZlZF8wKSAlPiUKICAgIGFycmFuZ2UoZGVzYyhyb3dfbnVtYmVyKCkpKSAlPiUKICAgIG11dGF0ZShhbHBoYSA9IGlzX3Rha2VyX3R4IC0gaXNfdGFrZXJfY3RsLAogICAgICAgICAgIGNhY2UgPSBvYnNlcnZlZF9pdHRfZWZmZWN0IC8gYWxwaGEpICU+JQogICAgcHJpbnQoKQp9KSkKYGBgCgoqKkJ1aWxkaW5nIGZyb20geW91ciBrbm93bGVkZ2UgZnJvbSB0aGUgbGFzdCBleGVyY2lzZSwgZGVzY3JpYmUgdGhlIG5ldyBjb2x1bW5zIGluIHRoZXNlIHRhYmxlczogaXNfdGFrZXJfdHgsIGlzX3Rha2VyX2N0bCwgb2JzZXJ2ZWRfaXR0X2VmZmVjdCwgYWxwaGEsIGFuZCBjYWNlLioqCgoqKldoYXQgaXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGlzX3Rha2VyX3R4LCBpc190YWtlcl9jdGwsIGFuZCBhbHBoYT8qKgoKKipXaGF0IGlzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBvYnNfaXR0LCBvYnNfYWxwaGEsIGFuZCBvYnNfY2FjZT8gKG9icyA9IG9ic2VydmVkKSoqCgoqKldoYXQgZG8geW91IG5vdGljZSBhYm91dCBhbHBoYSBhbmQgY2FjZSBhcyB0aGUgc2FtcGxlIHNpemUgaW5jcmVhc2VzPyoqCgpgYGB7cn0KCmBgYAoK